﻿using DotNetCommon.Extensions;
using NUnit.Framework;
using Shouldly;
using System;
using System.Linq.Expressions;
namespace DotNetCommon.Test.Extensions
{
    [TestFixture]
    public class ObjectTests_GetConvertExpr
    {
        [Test]
        public void TestSameType()
        {
            //int=>int
            var srcPara = Expression.Parameter(typeof(int));
            var destType = typeof(int);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int, int>>(expr, srcPara).Compile();
            func(1).ShouldBe(1);
        }

        [Test]
        public void TestNotNull2Null()
        {
            //int=>int?
            var srcPara = Expression.Parameter(typeof(int));
            var destType = typeof(int?);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int, int?>>(expr, srcPara).Compile();
            func(1).ShouldBe(1);
        }

        [Test]
        public void TestNull2NotNull()
        {
            //int?=>int
            var srcPara = Expression.Parameter(typeof(int?));
            var destType = typeof(int);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int?, int>>(expr, srcPara).Compile();
            func(1).ShouldBe(1);
        }

        [Test]
        public void TestNull2NotNull2()
        {
            //long?=>int
            var srcPara = Expression.Parameter(typeof(long?));
            var destType = typeof(int);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<long?, int>>(expr, srcPara).Compile();
            func(1L).ShouldBe(1);
        }

        [Test]
        public void TestInt2Long()
        {
            //int=>long
            var srcPara = Expression.Parameter(typeof(int));
            var destType = typeof(long);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int, long>>(expr, srcPara).Compile();
            func(1).ShouldBe(1);
        }

        #region other => string
        [Test]
        public void TestInt2Strig()
        {
            //int=>string
            var srcPara = Expression.Parameter(typeof(int));
            var destType = typeof(string);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int, string>>(expr, srcPara).Compile();
            func(1).ShouldBe("1");
        }
        [Test]
        public void TestIntNull2Strig()
        {
            //int?=>string
            var srcPara = Expression.Parameter(typeof(int?));
            var destType = typeof(string);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int?, string>>(expr, srcPara).Compile();
            func(1).ShouldBe("1");
            func(null).ShouldBe(null);
        }
        #endregion

        #region other => enum
        [Test]
        public void TestInt2Enum()
        {
            var srcPara = Expression.Parameter(typeof(int));
            var destType = typeof(EnumTest);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int, EnumTest>>(expr, srcPara).Compile();
            func(2).ShouldBe(EnumTest.Close);
        }
        [Test]
        public void TestIntNull2Enum()
        {
            var srcPara = Expression.Parameter(typeof(int?));
            var destType = typeof(EnumTest);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<int?, EnumTest>>(expr, srcPara).Compile();
            func(2).ShouldBe(EnumTest.Close);
        }
        [Test]
        public void TestString2Enum()
        {
            var srcPara = Expression.Parameter(typeof(string));
            var destType = typeof(EnumTest);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<string, EnumTest>>(expr, srcPara).Compile();
            func("1,2").ShouldBe(EnumTest.Open | EnumTest.Close);
        }
        [Test]
        public void TestArray2Enum()
        {
            var srcPara = Expression.Parameter(typeof(string[]));
            var destType = typeof(EnumTest);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<string[], EnumTest>>(expr, srcPara).Compile();
            func(["1", "2"]).ShouldBe(EnumTest.Open | EnumTest.Close);
        }
        #endregion

        #region DateTime/Guid => string
        [Test]
        public void TestDateTime2String()
        {
            //DateTime=>string
            var srcPara = Expression.Parameter(typeof(DateTime));
            var destType = typeof(string);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<DateTime, string>>(expr, srcPara).Compile();
            var t = func(DateTime.Parse("2025-01-23 21:42:01.123"));
            t.ShouldBe("2025/1/23 21:42:01");
        }

        [Test]
        public void TestDateTimeNull2String()
        {
            //DateTime=>string
            var srcPara = Expression.Parameter(typeof(DateTime?));
            var destType = typeof(string);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<DateTime?, string>>(expr, srcPara).Compile();
            var t = func(DateTime.Parse("2025-01-23 21:42:01.123"));
            t.ShouldBe("2025/1/23 21:42:01");
        }

        [Test]
        public void TestDateTimeNull2StringWithPara()
        {
            //DateTime=>string
            var srcPara = Expression.Parameter(typeof(DateTime?));
            var destType = typeof(string);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType, ["yyyy-MM-dd HH:mm:ss"]);
            var func = Expression.Lambda<Func<DateTime?, string>>(expr, srcPara).Compile();
            var t = func(DateTime.Parse("2025-01-23 21:42:01.123"));
            t.ShouldBe("2025-01-23 21:42:01");
        }

        [Test]
        public void TestGuidNull2StringWithPara()
        {
            //Guid=>string
            var srcPara = Expression.Parameter(typeof(Guid?));
            var destType = typeof(string);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType, ["N"]);
            var func = Expression.Lambda<Func<Guid?, string>>(expr, srcPara).Compile();
            var t = func(Guid.Parse("1".Repeat(32)));
            t.ShouldBe("1".Repeat(32));
        }
        #endregion

        #region FuZi
        [Flags]
        enum EnumTest { Open = 1, Close = 2, Other = 4 }
        class Fu { }
        class Zi : Fu { }
        [Test]
        public void TestZi2Fu()
        {
            //Zi=>Fu
            var srcPara = Expression.Parameter(typeof(Zi));
            var destType = typeof(Fu);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<Zi, Fu>>(expr, srcPara).Compile();
            var fu = func(new Zi());
            fu.ShouldNotBeNull();
        }
        #endregion

        #region 调用原来的 To()
        class Person
        {
            public int Id { get; set; }
        }

        [Test]
        public void Test()
        {
            //string=>OtherPerson
            var srcPara = Expression.Parameter(typeof(string));
            var destType = typeof(Person);
            var expr = ObjectExtensions.GetConvertExpr(srcPara, destType);
            var func = Expression.Lambda<Func<string, Person>>(expr, srcPara).Compile();
            var t = func(new Person { Id = 1 }.ToJson());
            t.GetType().ShouldBe(destType);
            t.Id.ShouldBe(1);
        }
        #endregion
    }
}
